# Promise
# Promise A+
实现一个符合 Promise A+规范的自定义 Promise,该实现可通过promises-aplus-tests (opens new window)全部测试
class MyPromise {
status = 'pending'
value = undefined
_fulfilled = []
_rejected = []
constructor(fn) {
const resolve = val => {
setTimeout(() => {
if (this.status !== 'pending') {
return
}
if (val instanceof MyPromise) {
// 如果 value 是个 Promise,递归执行
return val.then(resolve, reject)
}
this.value = val
this.status = 'fulfilled'
while (this._fulfilled.length) {
this._fulfilled.shift()()
}
})
}
const reject = err => {
setTimeout(() => {
if (this.status !== 'pending') {
return
}
this.value = err
this.status = 'rejected'
while (this._rejected.length) {
this._rejected.shift()()
}
})
}
try {
fn(resolve, reject)
} catch (e) {
reject(e)
}
}
then(onFulfilled, onRejected) {
let self = this
let p = new MyPromise((resolve, reject) => {
if (typeof onFulfilled !== 'function') {
onFulfilled = val => val
}
if (typeof onRejected !== 'function') {
onRejected = err => {
throw err
}
}
const fulfilledFn = function () {
try {
let r = onFulfilled(self.value)
resolveValue(r, p, resolve, reject)
} catch (err) {
reject(err)
}
}
const rejectedFn = function () {
try {
let r = onRejected(self.value)
resolveValue(r, p, resolve, reject)
} catch (err) {
reject(err)
}
}
if (this.status === 'pending') {
this._fulfilled.push(fulfilledFn)
this._rejected.push(rejectedFn)
} else if (this.status === 'fulfilled') {
setTimeout(() => {
fulfilledFn()
})
} else {
setTimeout(() => {
rejectedFn()
})
}
})
return p
}
catch(fn) {
return this.then(null, fn)
}
}
function resolveValue(result, currentPromise, resolve, reject) {
if (result === currentPromise) {
return reject(new TypeError('Error'))
}
if (result instanceof MyPromise) {
result.then(value => {
resolveValue(value, currentPromise, resolve, reject)
}, reject)
return
}
let called = false
if (result !== null && (typeof result === 'object' || typeof result === 'function')) {
try {
let then = result.then
if (typeof then === 'function') {
then.call(
result,
y => {
if (called) return
called = true
resolveValue(y, currentPromise, resolve, reject)
},
e => {
if (called) return
called = true
reject(e)
}
)
} else {
resolve(result)
}
} catch (e) {
if (called) return
called = true
reject(e)
}
} else {
resolve(result)
}
}
// 用于跑Promise的测试(promises-aplus-tests)用例
MyPromise.deferred = function () {
const deferred = {}
deferred.promise = new MyPromise((resolve, reject) => {
deferred.resolve = resolve
deferred.reject = reject
})
return deferred
}
module.exports = MyPromise
# 实现 Promise 的静态方法
# Promise.all
/**
* 实现Promise.all
* 参数未验证,主要实现原理
*/
Promise.all = function(promiseArray) {
return new Promise((resolve, reject) => {
let i = 0
const result = []
promiseArray.forEach((p, index) => {
p.then(
val => {
i++
result[index] = val
if (i === promiseArray.length) {
resolve(result)
}
},
err => reject(err)
)
})
})
}
# Promise.race
/**
* 实现Promise.race
* 参数未验证,主要实现原理
*/
Promise.race = function(promiseArray) {
return new Promise((resolve, reject) => {
let i = 0
promiseArray.forEach((p, index) => {
p.then(
val => resolve(val),
err => reject(err)
)
})
})
}
# Promise.allSettled
/**
* 实现Promise.allSettled
* 参数未验证,主要实现原理
*/
Promise.allSettled = function(promiseArray) {
return new Promise((resolve, reject) => {
let i = 0
const result = []
promiseArray.forEach((p, index) => {
p.then(
val => {
i++
result[index] = {
status: 'fulfilled',
value: val
}
if (i === promiseArray.length) {
resolve(result)
}
},
err => {
i++
result[index] = {
status: 'rejected',
value: err
}
if (i === promiseArray.length) {
resolve(result)
}
}
)
})
})
}
# 并行 Promise 与串行 Promise
一批函数执行后,如果有一个函数返回成功,则整个任务成功。分为串行和并行两种方式。使用场景举例:扫描服务器端口 0-65535。每次并发扫描10个端口,直到找到一个可用端口。
/**
* 给Promise添加parallelOnce和serialOnce两个静态方法
*/
export default class P extends Promise {
/**
* 并行执行多个Promise任务
* 当有一个fulfilled就让整个队列成功
* 如果没有一个任务fulfilled就rejected
* @param {Function[]} items
*/
static parallelOnce(items) {
return new Promise((resolve, reject) => {
let i = 0
items.forEach(item => {
item()
.then(val => {
resolve(val)
})
.catch(err => {
i++
if (i === items.length) {
reject(new Error('ALL_REJECTED'))
}
})
})
})
}
/**
* 串行执行多个Promise任务
* 当有一个fulfilled就让整个队列成功
* 如果没有一个任务fulfilled就rejected
* @param {Function[]} items
*/
static async serialOnce(items) {
for (let item of items) {
try {
return await item()
} catch (e) {}
}
throw new Error('ALL_REJECTED')
}
}